package org.example.service;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import okhttp3.*;
import okio.BufferedSource;
import org.example.service.TTSBridgeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * Ollama模型服务，用于调用本地Ollama API进行文本生成
 */
@Service
public class OlamaService {
    private static final Logger logger = LoggerFactory.getLogger(OlamaService.class);
    private final OkHttpClient httpClient;
    private final Gson gson = new Gson();

    @Value("${ollama.url:http://localhost:11434}")
    private String ollamaUrl;

    @Value("${ollama.model:qwen2.5:7b}")
    private String defaultModel;

    @Value("${ollama.timeout:60}")
    private int timeoutSeconds;

    @Autowired
    private TTSBridgeService ttsBridgeService;

    public OlamaService() {
        // 配置OkHttpClient，设置适当的超时
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(timeoutSeconds, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 同步方式调用Ollama API进行文本生成（非流式）
     *
     * @param prompt 输入提示文本
     * @param model  模型名称（可选，默认使用配置的模型）
     * @return 生成的文本
     */
    public String generateText(String prompt, String model) {
        if (model == null || model.trim().isEmpty()) {
            model = defaultModel;
        }

        try {
            // 使用Chat API端点
            String apiUrl = ollamaUrl + "/api/chat";

            // 构建请求对象 - 使用消息数组格式
            JsonObject requestBody = new JsonObject();
            requestBody.addProperty("model", model);

            // 创建messages数组
            com.google.gson.JsonArray messagesArray = new com.google.gson.JsonArray();
            JsonObject userMessage = new JsonObject();
            userMessage.addProperty("role", "user");
            userMessage.addProperty("content", prompt);
            messagesArray.add(userMessage);
            requestBody.add("messages", messagesArray);

            // 添加其他参数
            requestBody.addProperty("stream", false);
            requestBody.addProperty("temperature", 0.01);
            requestBody.addProperty("max_tokens", 1024);

            RequestBody body = RequestBody.create(
                    MediaType.parse("application/json"),
                    requestBody.toString());

            Request request = new Request.Builder()
                    .url(apiUrl)
                    .post(body)
                    .build();

            logger.info("正在调用Ollama Chat API生成文本，模型: {}, 提示: {}", model, prompt);
            try (Response response = httpClient.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    logger.error("Ollama API调用失败，状态码: {}", response.code());
                    return "调用AI模型失败，请稍后再试。";
                }

                String responseBody = response.body().string();
                JsonObject jsonResponse = gson.fromJson(responseBody, JsonObject.class);

                // 从新的响应格式中提取文本
                if (jsonResponse.has("message") && !jsonResponse.get("message").isJsonNull()) {
                    JsonObject message = jsonResponse.getAsJsonObject("message");
                    if (message.has("content") && !message.get("content").isJsonNull()) {
                        String generatedText = message.get("content").getAsString();
                        logger.info("Ollama API生成文本成功，长度: {} 字符", generatedText.length());
                        return generatedText;
                    }
                }

                logger.error("Ollama API返回格式不正确: {}", responseBody);
                return "AI模型返回格式异常，请稍后再试。";
            }
        } catch (Exception e) {
            logger.error("调用Ollama API时出错", e);
            return "调用AI模型时出错: " + e.getMessage();
        }
    }

    /**
     * 流式调用Ollama API，将结果实时发送给WebSocket客户端
     *
     * @param prompt    输入提示文本
     * @param model     模型名称（可选）
     * @param session   WebSocket会话
     * @param sessionId 会话ID
     * @return 包含完整生成文本的CompletableFuture
     */
    public CompletableFuture<String> generateTextStreaming(String prompt, String model, WebSocketSession session,
            String sessionId) {
        CompletableFuture<String> future = new CompletableFuture<>();

        if (model == null || model.trim().isEmpty()) {
            model = defaultModel;
        }

        try {
            // 使用新的chat API端点
            String apiUrl = ollamaUrl + "/api/chat";

            // 构建请求对象 - 使用新的消息数组格式
            JsonObject requestBody = new JsonObject();
            requestBody.addProperty("model", model);

            // 创建messages数组
            com.google.gson.JsonArray messagesArray = new com.google.gson.JsonArray();
            JsonObject userMessage = new JsonObject();
            userMessage.addProperty("role", "user");
            userMessage.addProperty("content", prompt);
            messagesArray.add(userMessage);
            requestBody.add("messages", messagesArray);

            // 添加其他参数
            requestBody.addProperty("stream", true);
            requestBody.addProperty("temperature", 0.01);
            requestBody.addProperty("max_tokens", 1024);

            RequestBody body = RequestBody.create(
                    MediaType.parse("application/json"),
                    requestBody.toString());

            Request request = new Request.Builder()
                    .url(apiUrl)
                    .post(body)
                    .build();

            logger.info("正在调用Ollama Chat API流式生成文本，模型: {}, 提示文本长度: {} 字符, 会话ID: {}",
                    model, prompt.length(), sessionId);

            // 使用异步调用
            StringBuilder fullText = new StringBuilder();

            httpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    logger.error("Ollama API流式调用失败", e);
                    try {
                        // 发送错误消息给客户端
                        JsonObject errorMsg = new JsonObject();
                        errorMsg.addProperty("type", "ai_error");
                        errorMsg.addProperty("message", "调用AI模型失败: " + e.getMessage());
                        errorMsg.addProperty("session_id", sessionId);
                        session.sendMessage(new TextMessage(errorMsg.toString()));

                        future.completeExceptionally(e);
                    } catch (IOException ex) {
                        logger.error("发送错误消息失败", ex);
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (!response.isSuccessful()) {
                        logger.error("Ollama API流式调用返回错误，状态码: {}", response.code());
                        String errorBody = response.body().string();
                        logger.error("错误详情: {}", errorBody);

                        try {
                            // 发送错误消息给客户端
                            JsonObject errorMsg = new JsonObject();
                            errorMsg.addProperty("type", "ai_error");
                            errorMsg.addProperty("message", "调用AI模型失败，状态码: " + response.code());
                            errorMsg.addProperty("session_id", sessionId);
                            session.sendMessage(new TextMessage(errorMsg.toString()));

                            future.completeExceptionally(new RuntimeException("API调用失败，状态码: " + response.code()));
                        } catch (IOException ex) {
                            logger.error("发送错误消息失败", ex);
                        }
                        return;
                    }

                    try (ResponseBody responseBody = response.body()) {
                        if (responseBody == null) {
                            logger.error("Ollama API返回空响应体");
                            future.completeExceptionally(new RuntimeException("API返回空响应"));
                            return;
                        }

                        // 读取流式响应
                        String line;
                        try (BufferedSource source = responseBody.source()) {
                            while ((line = source.readUtf8Line()) != null) {
                                if (line.trim().isEmpty()) {
                                    continue;
                                }

                                try {
                                    // 解析每行JSON，适配新的响应格式
                                    JsonObject chunk = gson.fromJson(line, JsonObject.class);

                                    // 新的API返回格式是通过message对象中的content获取文本
                                    if (chunk.has("message") && !chunk.get("message").isJsonNull()) {
                                        JsonObject message = chunk.getAsJsonObject("message");
                                        if (message.has("content") && !message.get("content").isJsonNull()) {
                                            String textChunk = message.get("content").getAsString();

                                            // 有时API会返回空字符串作为最后一个块，跳过它们
                                            if (textChunk.trim().isEmpty() && chunk.has("done")
                                                    && chunk.get("done").getAsBoolean()) {
                                                logger.debug("跳过空的结束块，但检测到done=true，将完成处理");
                                                // 即使是空块，如果标记为done，也应该完成future
                                                logger.info("Ollama API流式生成完成，总长度: {} 字符, 会话ID: {}",
                                                        fullText.length(), sessionId);
                                                future.complete(fullText.toString());
                                                break;
                                            }

                                            fullText.append(textChunk);

                                            // 添加更详细的日志，记录每个文本块
                                            logger.debug("收到文本块[{}]: '{}', 会话ID: {}",
                                                    textChunk.length(), textChunk, sessionId);

                                            // 创建发送给客户端的消息
                                            JsonObject wsMessage = new JsonObject();
                                            wsMessage.addProperty("type", "ai_response");
                                            wsMessage.addProperty("text", textChunk);
                                            wsMessage.addProperty("full_text", fullText.toString());
                                            boolean isDone = chunk.has("done") && chunk.get("done").getAsBoolean();
                                            wsMessage.addProperty("done", isDone);
                                            wsMessage.addProperty("session_id", sessionId);

                                            // 发送到WebSocket并确保消息发送成功
                                            try {
                                                // 添加发送前的日志
                                                logger.info("正在发送文本块到前端, 长度: {}, 会话ID: {}",
                                                        textChunk.length(), sessionId);

                                                // 发送消息
                                                session.sendMessage(new TextMessage(wsMessage.toString()));

                                                // 尝试刷新WebSocket连接
                                                try {
                                                    if (session instanceof org.springframework.web.socket.adapter.standard.StandardWebSocketSession) {
                                                        ((org.springframework.web.socket.adapter.standard.StandardWebSocketSession) session)
                                                                .getNativeSession().getBasicRemote().flushBatch();
                                                        logger.debug("成功刷新WebSocket连接");
                                                    } else {
                                                        // 记录会话类型，帮助调试
                                                        logger.debug("WebSocket会话类型: {}", session.getClass().getName());
                                                    }
                                                } catch (Exception e) {
                                                    logger.warn("尝试刷新WebSocket连接时出错: {}", e.getMessage());
                                                }

                                                // 添加延迟，避免消息发送过快
                                                try {
                                                    // 使用更短的延迟时间，同时保证消息能被处理
                                                    Thread.sleep(5);
                                                } catch (InterruptedException ie) {
                                                    Thread.currentThread().interrupt();
                                                }

                                                // 每隔几个文本块刷新一次WebSocket状态，确保前端即时收到
                                                if (fullText.length() % 20 == 0) {
                                                    logger.debug("定期检查WebSocket状态，当前文本长度: {}", fullText.length());
                                                    if (session.isOpen()) {
                                                        logger.debug("WebSocket连接正常");
                                                    } else {
                                                        logger.warn("WebSocket连接已关闭，无法继续发送消息");
                                                    }
                                                }
                                            } catch (Exception e) {
                                                logger.error("发送文本块到WebSocket失败: {}", e.getMessage(), e);
                                                // 尝试发送错误通知
                                                try {
                                                    JsonObject errorMsg = new JsonObject();
                                                    errorMsg.addProperty("type", "error");
                                                    errorMsg.addProperty("message", "发送AI响应失败: " + e.getMessage());
                                                    session.sendMessage(new TextMessage(errorMsg.toString()));
                                                } catch (Exception ex) {
                                                    logger.error("发送错误消息也失败了: {}", ex.getMessage());
                                                }
                                            }

                                            // 如果是最后一个块，完成future
                                            if (isDone) {
                                                logger.info("Ollama API流式生成完成，总长度: {} 字符, 会话ID: {}",
                                                        fullText.length(), sessionId);

                                                // 生成完成，会由thenAccept中负责更新状态
                                                future.complete(fullText.toString());
                                                break;
                                            }
                                        }
                                    }
                                } catch (Exception e) {
                                    logger.error("解析Ollama API响应时出错", e);
                                }
                            }
                        }
                    } catch (Exception e) {
                        logger.error("读取Ollama API流式响应时出错", e);
                        future.completeExceptionally(e);
                    }
                }
            });
            logger.error("开始调用TTS API,{}", future);
            return future;

        } catch (Exception e) {
            logger.error("准备调用Ollama API时出错", e);
            future.completeExceptionally(e);
            return future;
        }
    }

    /**
     * 将SenseVoice识别的文本传递给Ollama模型，并将生成的回复发送到TTS流程
     * 这是一个重载方法，提供更多配置选项
     * 
     * @param recognizedText   识别的文本
     * @param websocketSession WebSocket会话
     * @param sessionId        会话ID
     * @param voiceService     语音服务，用于TTS处理
     * @param speaker          指定的说话人(音色ID)
     * @param model            指定的AI模型
     * @param ttsOptions       TTS相关配置参数，如速度、音量等
     */
    public void processRecognizedTextWithAI(String recognizedText, WebSocketSession websocketSession,
            String sessionId, VoiceService voiceService, String speaker, String model, JsonObject ttsOptions) {
        if (recognizedText == null || recognizedText.trim().isEmpty()) {
            logger.warn("收到空的识别文本，跳过AI处理，会话ID: {}", sessionId);
            return;
        }

        // 如果未指定说话人，使用默认值
        if (speaker == null || speaker.trim().isEmpty()) {
            speaker = "中文女"; // 默认发言人
        }

        // 记录更详细的处理信息
        logger.info("处理识别文本: \"{}\", 使用模型: {}, 说话人: {}, 会话ID: {}",
                recognizedText, (model != null ? model : defaultModel), speaker, sessionId);

        // 通知前端AI处理已经开始
        try {
            JsonObject processingMsg = new JsonObject();
            processingMsg.addProperty("type", "ai_processing");
            processingMsg.addProperty("status", "started");
            processingMsg.addProperty("text", recognizedText);
            processingMsg.addProperty("session_id", sessionId);
            // 添加额外信息
            if (model != null) {
                processingMsg.addProperty("model", model);
            }
            if (speaker != null) {
                processingMsg.addProperty("speaker", speaker);
            }
            websocketSession.sendMessage(new TextMessage(processingMsg.toString()));

            // 更新AI处理状态为正在处理
            updateAiProcessingStatusInWebSocketHandler(sessionId, websocketSession, true);

            logger.info("已通知前端AI处理开始, 会话ID: {}", sessionId);
        } catch (Exception e) {
            logger.error("发送AI处理开始通知失败", e);
        }

        // 启动流式生成
        final String finalSpeaker = speaker; // 创建一个final副本，用于lambda表达式
        generateTextStreaming(recognizedText, model, websocketSession, sessionId)
                .thenAccept(fullResponse -> {
                    try {
                        // 确保生成的文本不为空
                        if (fullResponse == null || fullResponse.trim().isEmpty()) {
                            logger.warn("AI生成的文本为空，跳过TTS处理，会话ID: {}", sessionId);
                            // 即使没有文本也要更新状态
                            updateAiProcessingStatusInWebSocketHandler(sessionId, websocketSession, false);
                            return;
                        }

                        logger.info("AI响应完成，准备生成TTS，文本长度: {}, 会话ID: {}", fullResponse.length(), sessionId);

                        // 使用TTSBridgeService处理TTS生成
                        // 这样可以避免在流式输出的过程中过早发送TTS请求
                        ttsBridgeService.processTTSForAIResponse(sessionId, fullResponse, finalSpeaker);

                        // AI处理完成，更新状态
                        updateAiProcessingStatusInWebSocketHandler(sessionId, websocketSession, false);
                    } catch (Exception e) {
                        logger.error("处理AI响应时出错", e);
                        try {
                            // 发生错误时也要重置AI处理状态
                            updateAiProcessingStatusInWebSocketHandler(sessionId, websocketSession, false);

                            // 通知前端处理出错
                            JsonObject errorMsg = new JsonObject();
                            errorMsg.addProperty("type", "error");
                            errorMsg.addProperty("message", "处理AI响应时出错: " + e.getMessage());
                            errorMsg.addProperty("session_id", sessionId);
                            websocketSession.sendMessage(new TextMessage(errorMsg.toString()));
                        } catch (Exception ex) {
                            logger.error("重置AI处理状态或发送错误通知失败", ex);
                        }
                    }
                })
                .exceptionally(ex -> {
                    logger.error("生成AI响应时出错", ex);
                    try {
                        // 发生异常时也要重置AI处理状态
                        updateAiProcessingStatusInWebSocketHandler(sessionId, websocketSession, false);

                        // 发送错误消息
                        JsonObject errorMsg = new JsonObject();
                        errorMsg.addProperty("type", "error");
                        errorMsg.addProperty("message", "AI处理失败: " + ex.getMessage());
                        errorMsg.addProperty("session_id", sessionId);
                        websocketSession.sendMessage(new TextMessage(errorMsg.toString()));
                    } catch (Exception e) {
                        logger.error("发送错误消息失败", e);
                    }
                    return null;
                });
    }

    /**
     * 将SenseVoice识别的文本传递给Ollama模型，并将生成的回复发送到TTS流程
     * 这是一个简化版本，使用默认参数
     * 
     * @param recognizedText   识别的文本
     * @param websocketSession WebSocket会话
     * @param sessionId        会话ID
     * @param voiceService     语音服务，用于TTS处理
     */
    public void processRecognizedTextWithAI(String recognizedText, WebSocketSession websocketSession,
            String sessionId, VoiceService voiceService) {
        processRecognizedTextWithAI(recognizedText, websocketSession, sessionId, voiceService, "中文女", null, null);
    }

    /**
     * 更新AI处理状态
     *
     * @param sessionId        会话ID
     * @param websocketSession WebSocket会话
     * @param isProcessing     是否正在处理
     */
    private void updateAiProcessingStatusInWebSocketHandler(String sessionId, WebSocketSession websocketSession,
            boolean isProcessing) {
        try {
            // 使用TTSBridgeService更新AI处理状态
            ttsBridgeService.updateAiProcessingStatus(sessionId, isProcessing);

            logger.info("已更新AI处理状态: {}, 会话ID: {}", isProcessing ? "处理中" : "已完成", sessionId);
        } catch (Exception e) {
            logger.error("更新AI处理状态失败", e);
        }
    }
}